const { User, Menu, Role } = require("../../models");
const { Op } = require("sequelize");
const { success, failure } = require("../../utils/responses");
const { paging } = require("../../utils/utils");
const { NotFoundError } = require("../../utils/errors");

/**
 * 获取动态路由
 * @param req
 * @param res
 */
exports.getAsyncRoutes = async (req, res) => {
  try {
    // 排序
    const condition = {
      raw: true, //只返回数据的参数 --默认返回包装类
    };
    const rows = await Menu.findAll(condition);
    // 返回
    const menuIds = await getUserRoles(req);
    success(res, "查询成功", getTheMenuStructure(rows, "0", menuIds));
  } catch (error) {
    failure(res, error);
  }
};

/**
 * 分页数据列表
 * @param req
 * @param res
 */
exports.list = async (req, res) => {
  // 查询所有数据
  try {
    // 获取分页参数
    const { query, currentPage, pageSize, offset } = paging(req);
    // 排序+分页
    const condition = {
      order: [
        ["rank", "DESC"],
        ["id", "ASC"],
      ],
      limit: pageSize,
      offset: offset,
    };
    // 模糊查询
    if (query.name) {
      condition.where = {
        name: {
          [Op.like]: `%${query.name}%`,
        },
      };
    }
    condition.where = {
      parentId: {
        [Op.eq]: query.parentId || "0", //根元素
      },
    };
    // 分页查询
    const { count, rows } = await Menu.findAndCountAll(condition);
    // 返回
    success(res, "查询成功", {
      lists: rows,
      pagination: {
        total: count,
        currentPage,
        pageSize,
      },
    });
  } catch (error) {
    failure(res, error);
  }
};

/**
 * 所有数据列
 * @param req
 * @param res
 */
exports.all = async (req, res) => {
  try {
    const { query } = paging(req);
    // 排序
    const condition = {
      raw: true, //只返回数据的参数 --默认返回包装类
    };
    // 模糊查询
    if (query.name) {
      condition.where = {
        name: {
          [Op.like]: `%${query.name}%`,
        },
      };
    }

    const rows = await Menu.findAll(condition);
    // 返回
    success(res, "查询成功", rows);
  } catch (error) {
    failure(res, error);
  }
};

/**
 * 添加
 * @param req
 * @param res
 */
exports.add = async (req, res) => {
  try {
    const body = filterBody(req);
    delete body["id"];
    const data = await Menu.create(body);
    success(res, "创建成功", data, 201);
  } catch (error) {
    failure(res, error);
  }
};

/**
 * 更新菜单
 * @param req
 * @param res
 */
exports.update = async (req, res) => {
  try {
    const data = await getById(req);
    const body = filterBody(req);
    await data.update(body); //删除
    success(res, "更新菜单成功", data);
  } catch (error) {
    failure(res, error);
  }
};

/**
 * 详情
 * @param req
 * @param res
 */
exports.details = async (req, res) => {
  try {
    const data = await getById(req);
    success(res, "查询成功", data);
  } catch (error) {
    failure(res, error);
  }
};

/**
 * 删除
 * @param req
 * @param res
 */
exports.del = async (req, res) => {
  try {
    const data = await getById(req);
    await data.destroy();
    success(res, "删除成功");
  } catch (error) {
    failure(res, error);
  }
};

/**
 * 获取当前
 * @param req
 */
async function getById(req) {
  const id = req.body.id || req.params.id || req.query.id;
  if (!id) {
    throw new NotFoundError(`ID: 参数错误`);
  }
  // 获取当前菜单
  const data = await Menu.findByPk(id);
  if (!data) {
    throw new NotFoundError(`ID: ${id} not found`);
  }
  return data;
}

/**
 * 公共方法过滤白名单
 * @param req
 * @returns {*}
 */
function filterBody(req) {
  return {
    menuType: req.body.menuType,
    parentId: req.body.parentId,
    title: req.body.title,
    name: req.body.name,
    path: req.body.path,
    component: req.body.component,
    rank: req.body.rank,
    redirect: req.body.redirect,
    icon: req.body.icon,
    extraIcon: req.body.extraIcon,
    enterTransition: req.body.enterTransition,
    leaveTransition: req.body.leaveTransition,
    activePath: req.body.activePath,
    auths: req.body.auths,
    frameSrc: req.body.frameSrc,
    frameLoading: req.body.frameLoading,
    keepAlive: req.body.keepAlive,
    hiddenTag: req.body.hiddenTag,
    fixedTag: req.body.fixedTag,
    showLink: req.body.showLink,
    showParent: req.body.showParent,
  };
}

/**
 * 获取菜单结构
 * @param parentId
 * @param data
 * @param menuIds
 * @returns {*[]}
 */
function getTheMenuStructure(data, parentId = "0", menuIds = []) {
  const result = [];
  data.forEach((item) => {
    if (parseInt(item.parentId) === parseInt(parentId) && item.menuType !== 3) {
      //  字段注释 modelGenerate/menuTable.js
      const {
        path,
        name,
        component,
        redirect,
        title,
        icon,
        showLink,
        rank,
        extraIcon,
        showParent,
        keepAlive,
        frameSrc,
        frameLoading,
        hiddenTag,
        fixedTag,
        dynamicLevel,
        activePath,
        enterTransition,
        leaveTransition,
      } = item;

      // 获取用户的菜单权限
      const rolesName = [];
      menuIds.forEach((menu) => {
        if (menu.menuId.some((ele) => ele === item.id)) {
          rolesName.push(menu.name);
        }
      });

      // 整体路由配置表
      const routeConfigsTable = {
        path,
        name,
        component,
        redirect,
        meta: {
          title,
          icon,
          rank,
          extraIcon,
          frameSrc,
          activePath,
          dynamicLevel,
          showLink: showLink === 1,
          showParent: showParent === 1,
          keepAlive: keepAlive === 1,
          frameLoading: frameLoading === 1,
          hiddenTag: hiddenTag === 1,
          fixedTag: fixedTag === 1,
          transition: {
            enterTransition,
            leaveTransition,
          },
          roles: rolesName, //获取当前用户的角色
          auths: [...getAuths(data, item.id)],
        },
      };
      const children = getTheMenuStructure(data, item.id, menuIds);
      // 不能传入空的children属性
      if (children.length > 0) {
        routeConfigsTable.children = children;
      }
      result.push(routeConfigsTable);
    }
  });
  return result;
}

/**
 * 获取当前用户的角色权限
 * @param req
 * @returns {Promise<*[]>}
 */
async function getUserRoles(req) {
  const rolesData = (req.user.rolesId = JSON.parse(req.user.rolesId || "[]"));
  const menuIds = [];
  for (const id of rolesData) {
    const role = await Role.findByPk(id);
    menuIds.push({
      menuId: JSON.parse(role.menuId || "[]"),
      name: role.name,
    });
  }
  return menuIds;
}

/**
 * 获取按钮权限
 * @param data
 * @param id
 * @returns {*[]}
 */
function getAuths(data, id) {
  const dataMap = data.filter((item) => {
    return item.menuType === 3;
  });
  const auths = [];
  dataMap.forEach((item) => {
    if (parseInt(item.parentId) === parseInt(id)) {
      auths.push("permission:btn:" + item.auths);
    }
  });
  return auths;
}
